import java.awt.Point;
import java.awt.Rectangle;
import java.util.Random;

public class PLAttribLineLine extends PLAttrib {	
	private static final long serialVersionUID = 1L;

	protected PLFactor mLength = new PLFactor(PLFactor.GetDefaultRatioSet());	
	protected PLFactor mSlopeAngle = new PLFactor(PLFactor.GetDefaultPiDeltaSet());	
	protected PLFactorMatch[] mQuadrants = new PLFactorMatch[2];	
	protected PLFactor[] mDistances = new PLFactor[4];	
	
	public PLAttribLineLine() {
		super();

		for (int i = 0; i < mQuadrants.length; ++ i) {
			mQuadrants[i] = new PLFactorMatch();
		}

		for (int i = 0; i < mDistances.length; ++ i) {
			mDistances[i] = new PLFactor(PLFactor.GetDefaultDistanceDeltaSet());
		}
	}

	public float GetLength() {return mLength.GetAValue();}
	public float GetSlopeAngle() {return mSlopeAngle.GetAValue();}
	public int GetQuadrant(int index) {return (int) mQuadrants[index].GetAValue();}
	public int GetDistance(int index) {return (int) mDistances[index].GetAValue();}

	public float BuildResponse(PLShape inQuery, PLOutShape outResponse) {

		Random generator = new Random();

		PLLine query = (PLLine)inQuery;

		// quadrants
		int neg = (generator.nextInt(2) == 1) ? 1: -1;
		
		int startingQuadrand = (query.GetStartingQuadrant() + neg*GetQuadrant(0) + 4) % 4;
		int endingQuadrand = (query.GetEndingQuardrant() + neg*GetQuadrant(1) + 4) % 4;

		// starting point		
		Point sPoint =  new Point(generator.nextInt(PLGuiInfo.Obj().GetWidth()/2), generator.nextInt(PLGuiInfo.Obj().GetHeight()/2));		
		Rectangle sQuad = PLShapeUtils.GetQuadrantRect(startingQuadrand);
		sPoint.x += (int)sQuad.getX();
		sPoint.y += (int)sQuad.getY();		

		// length
		float length = query.GetLength()*GetLength();

		// slope
		float slopeAngle = query.GetSlopeAngle();	
		slopeAngle += (generator.nextInt(2) == 1) ? GetSlopeAngle(): -1* GetSlopeAngle();

		// end point
		Point[] endPoints = PLShapeUtils.GetPossibleEndPoints(sPoint, slopeAngle, length);
		Point eBestPoint = endPoints[0];

		int QuadDiff1 = Math.abs(PLShapeUtils.GetQuadrant(endPoints[0]) - endingQuadrand);
		int QuadDiff2 = Math.abs(PLShapeUtils.GetQuadrant(endPoints[1]) - endingQuadrand);
		
		if (QuadDiff2 < QuadDiff1 || (QuadDiff2 == QuadDiff1  && (generator.nextInt(2) == 1))) {
			eBestPoint.setLocation(endPoints[1]);
		}

		outResponse.SetShape(new PLLine(sPoint, eBestPoint));
				
		return 1;
	}

	public void Update(PLShape inQuery, PLShape inResponse) {
		PLLine query = (PLLine)inQuery;
		PLLine response = (PLLine)inResponse;
		
		UpdateLength(query.GetLength(), response.GetLength());
		UpdateSlope(query.GetSlopeAngle(), response.GetSlopeAngle());

		UpdateQuadrant(0, query.GetStartingQuadrant(), response.GetStartingQuadrant());
		UpdateQuadrant(1, query.GetEndingQuardrant(), response.GetEndingQuardrant());	

		UPdateDistance(0, query.GetStart() , response.GetStart());  // s, s 
		UPdateDistance(1, query.GetStart() , response.GetEnd());  // s, e 
		UPdateDistance(2, query.GetEnd() , response.GetStart());  // e, s 
		UPdateDistance(3, query.GetEnd() , response.GetEnd());  // e, e 
	}

	// Protected
	protected void UpdateLength(float qLength, float rLength) {
		if ( rLength!= 0)
			mLength.Update(rLength/qLength);
	}

	protected void UpdateSlope(float qSlope, float rSlope) {
		mSlopeAngle.Update(Math.abs(rSlope - qSlope));
	}

	protected void UpdateQuadrant(int index, int qQuadrant, int rQuadrant) {		
		int cDelta = Math.abs(qQuadrant - rQuadrant);
		if (cDelta == 3)  cDelta = 1;
		
		mQuadrants[index].Update(cDelta);
	}

	// index : 0 = ss, 1 = se, 2 = es, 3 = ee
	protected void UPdateDistance(int index, Point qPoint, Point rPoint) {			
		mDistances[index].Update(PLShapeUtils.GetDistance(qPoint, rPoint));
	}
	
}
